package controllers

import (
	"encoding/json"
	"errors"
	"gitee.com/lzqysoft/ga_wz_backend/libs/encrypt"
	"gitee.com/lzqysoft/ga_wz_backend/models"
	"github.com/astaxie/beego/orm"

	//	"strconv"

	"strings"
	"time"

	"github.com/astaxie/beego"
)

// FlowController operations for Flow
type FlowController struct {
	CommonController
}

// URLMapping 方法映射
func (c *FlowController) URLMapping() {
	c.Mapping("Post", c.Post)
	c.Mapping("GetOne", c.GetOne)
	c.Mapping("GetAll", c.GetAll)
	c.Mapping("Update", c.Update)
	c.Mapping("Delete", c.Delete)
	c.Mapping("GetBusyDoing", c.GetBusyDoing)
	c.Mapping("GetBusyFlowing", c.GetBusyFlowing)
	c.Mapping("GetBusyFinish", c.GetBusyFinish)
	c.Mapping("FlowStart", c.FlowStart)
	c.Mapping("GetAssetsbuyDoing", c.GetAssetsbuyDoing)
	c.Mapping("GetStateinsByBusy", c.GetStateinsByBusy)
	c.Mapping("FlowApprove", c.FlowApprove)
	c.Mapping("GetAssetsbuyCompleted", c.GetAssetsbuyCompleted)
	c.Mapping("GetAssetsbuyFinish", c.GetAssetsbuyFinish)
	c.Mapping("GetAssetsbuyUserAndBusy", c.GetAssetsbuyUserAndBusy)

}

// Edge 流程转换规则
type Edge struct {
	Id        string   `json:"id"`
	Action    string   `json:"action"`
	Event     string   `json:"event"`
	LabelText string   `json:"labelText"`
	Source    string   `json:"source"`
	Target    string   `json:"target"`
	Uuids     []string `json:"uuids"`
}

// Node 流程节点
type Node struct {
	ClassName string `json:"className"`
	Id        string `json:"id"`
	Role      string `json:"role"`
	Style     Stytle `json:"style"`
	Text      string `json:"text"`
	Status    string `json:"status"`
	Time      string `json:"time"`
}

// FlowSt 流程
type FlowSt struct {
	Flow  models.Flow `json:"flow"`
	Edges []Edge      `json:"edges"`
	Nodes []Node      `json:"nodes"`
}

// FlowInst 流程实例
type FlowInst struct {
	Flow  models.Flowinstance `json:"flow"`
	Edges []Edge              `json:"edges"`
	Nodes []Node              `json:"nodes"`
}

// Post ...
// @Title Post
// @Description create Flow
// @Param	body		body 	models.Flow	true		"body for Flow content"
// @Success 201 {int} models.Flow
// @Failure 403 body is empty
// @router / [post]
func (c *FlowController) Post() {
	user := c.User
	rdata, err := c.AesDecodeToByte(c.GetString("tdata"))
	if err != nil {
		c.RetError(ErrToken)
	}
	var flow FlowSt
	var nodes []*models.State
	var edges []*models.Transition

	if err := json.Unmarshal(rdata, &flow); err != nil {
		beego.Error(err)
		c.RetError(ErrInputData)
	}
	for _, v := range flow.Nodes {
		var node models.State
		node.Id = v.Id
		node.Flow = &flow.Flow
		node.RoleId = v.Role
		node.Classname = v.ClassName
		node.Text = v.Text
		node.Ctime = time.Now()
		node.Creater = user.Name
		node.Utime = time.Now()
		node.Updater = user.Name
		node.Isdelete = 0
		node.Status = 1
		beego.Debug(v.Style)
		style, _ := json.Marshal(v.Style)
		node.Style = string(style)
		// node.Style = v.Style
		switch node.Classname {
		case "start":
			flow.Flow.Start = node.Id
		case "end":
			flow.Flow.End = node.Id
		}
		beego.Debug(node)
		nodes = append(nodes, &node)
	}
	for _, v := range flow.Edges {
		var edge models.Transition
		edge.Id = encrypt.GetGuid()
		edge.Action, _ = models.GetActionById(v.Action)
		edge.EventId = v.Event
		edge.Name = v.LabelText
		edge.From = v.Source
		edge.To = v.Target
		edge.Fromid = v.Uuids[0]
		edge.Toid = v.Uuids[1]
		edge.Flow = &flow.Flow
		edge.Ctime = time.Now()
		edge.Creater = user.Name
		edge.Utime = time.Now()
		edge.Updater = user.Name
		edge.Isdelete = 0
		edge.Status = 1
		beego.Debug(edge)
		edges = append(edges, &edge)
	}
	flow.Flow.Ctime = time.Now()
	flow.Flow.Creater = user.Name
	flow.Flow.Utime = time.Now()
	flow.Flow.Updater = user.Name
	flow.Flow.Isdelete = 0
	flow.Flow.Busyname = flow.Flow.Name
	flow.Flow.Status = 1
	if err := models.CreateFlow(&flow.Flow, nodes, edges); err != nil {
		beego.Error(err)
		c.RetError(ErrDatabase)
	}
	c.Dlog("添加了流程,id是:", flow.Flow.Id)
	c.RetSuccess(flow)
}

// GetOne ...
// @Title Get One
// @Description get Flow by id
// @Param	id		path 	string	true		"The key for staticblock"
// @Success 200 {object} models.Flow
// @Failure 403 :id is empty
// @router /:id [get]
func (c *FlowController) GetOne() {
	// rdata, err := c.AesDecode(c.GetString("tdata"))
	// beego.Debug(c.Ctx.Input.Param())
	beego.Debug(c.GetString("id"))
	id := c.Ctx.Input.Param(":id")
	beego.Debug(id)
	v, err := models.GetFlowById(id)
	if err != nil {
		c.RetError(ErrNoData)
	}
	var f FlowSt

	f.Flow = *v
	for _, e := range v.States {
		var node Node
		node.Id = e.Id
		node.ClassName = e.Classname
		node.Role = e.RoleId
		node.Text = e.Text
		json.Unmarshal([]byte(e.Style), &node.Style)
		f.Nodes = append(f.Nodes, node)
	}
	for _, e := range v.Transitions {
		var edge Edge
		edge.Id = e.Id
		edge.Action = e.Action.Id
		edge.Event = e.EventId
		edge.LabelText = e.Name
		edge.Source = e.From
		edge.Target = e.To
		edge.Uuids = append(edge.Uuids, e.Fromid, e.Toid)
		f.Edges = append(f.Edges, edge)
	}
	// f.Nodes = append(f.Nodes)
	c.RetSuccess(f)
	// c.Data["json"] = v
	// c.ServeJSON()
}

// GetAll ...
// @Title Get All
// @Description get Flow
// @Param	query	query	string	false	"Filter. e.g. col1:v1,col2:v2 ..."
// @Param	fields	query	string	false	"Fields returned. e.g. col1,col2 ..."
// @Param	sortby	query	string	false	"Sorted-by fields. e.g. col1,col2 ..."
// @Param	order	query	string	false	"Order corresponding to each sortby field, if single value, apply to all sortby fields. e.g. desc,asc ..."
// @Param	limit	query	string	false	"Limit the size of result set. Must be an integer"
// @Param	offset	query	string	false	"Start position of result set. Must be an integer"
// @Success 200 {object} models.Flow
// @Failure 403
// @router / [get]
func (c *FlowController) GetAll() {
	var fields []string
	var sortby []string
	var order []string
	var query = make(map[string]string)
	var limit int64 = 10
	var offset int64

	// fields: col1,col2,entity.col3
	if v := c.GetString("fields"); v != "" {
		fields = strings.Split(v, ",")
	}
	// limit: 10 (default is 10)
	if v, err := c.GetInt64("limit"); err == nil {
		limit = v
	}
	// offset: 0 (default is 0)
	if v, err := c.GetInt64("offset"); err == nil {
		offset = v
	}
	// sortby: col1,col2
	if v := c.GetString("sortby"); v != "" {
		sortby = strings.Split(v, ",")
	}
	// order: desc,asc
	if v := c.GetString("order"); v != "" {
		order = strings.Split(v, ",")
	}
	// query: k:v,k:v
	if v := c.GetString("query"); v != "" {
		for _, cond := range strings.Split(v, ",") {
			kv := strings.SplitN(cond, ":", 2)
			if len(kv) != 2 {
				c.Data["json"] = errors.New("Error: invalid query key/value pair")
				c.ServeJSON()
				return
			}
			k, v := kv[0], kv[1]
			query[k] = v
		}
	}
	limit = -1
	query["Isdelete"] = "0"
	query["Status"] = "1"
	l, err := models.GetAllFlow(query, fields, sortby, order, offset, limit)
	if err != nil {
		beego.Error("err is :", err)
		c.RetError(ErrDatabase)
	} else {
		c.RetSuccess(l)
	}
}

// Update ...
// @Title Update
// @Description update the Flow
// @Param	id		path 	string	true		"The id you want to update"
// @Param	body		body 	models.Flow	true		"body for Flow content"
// @Success 200 {object} models.Flow
// @Failure 403 :id is not int
// @router /Update [post]
func (c *FlowController) Update() {
	user := c.User
	rdata, err := c.AesDecodeToByte(c.GetString("tdata"))
	if err != nil {
		c.RetError(ErrToken)
	}
	var flow FlowSt
	var nodes []*models.State
	var edges []*models.Transition

	if err := json.Unmarshal(rdata, &flow); err != nil {
		beego.Error(err)
		c.RetError(ErrInputData)
	}
	err = models.SoftDeleteFlow(flow.Flow.Id, user.Name)
	if err != nil {
		beego.Error(err)
		c.RetError(ErrDatabase)
	}
	flow.Flow.Ctime = time.Now()
	flow.Flow.Creater = user.Name
	flow.Flow.Utime = time.Now()
	flow.Flow.Updater = user.Name
	flow.Flow.Isdelete = 0
	flow.Flow.Status = 1
	//新添加流程
	flow.Flow.Id = encrypt.GetGuid()
	for _, v := range flow.Nodes {
		var node models.State
		node.Id = "new" + v.Id
		node.Flow = &flow.Flow
		node.RoleId = v.Role
		node.Classname = v.ClassName
		node.Text = v.Text
		node.Ctime = time.Now()
		node.Creater = user.Name
		node.Utime = time.Now()
		node.Updater = user.Name
		node.Isdelete = 0
		node.Status = 1
		beego.Debug(v.Style)
		style, _ := json.Marshal(v.Style)
		node.Style = string(style)
		// node.Style = v.Style
		switch node.Classname {
		case "start":
			flow.Flow.Start = node.Id
		case "end":
			flow.Flow.End = node.Id
		}
		beego.Debug(node)
		nodes = append(nodes, &node)
	}
	for _, v := range flow.Edges {
		var edge models.Transition
		edge.Id = encrypt.GetGuid()
		edge.Action, _ = models.GetActionById(v.Action)
		edge.EventId = v.Event
		edge.Name = v.LabelText
		edge.From = "new" + v.Source
		edge.To = "new" + v.Target
		edge.Fromid = "new" + v.Uuids[0]
		edge.Toid = "new" + v.Uuids[1]
		edge.Flow = &flow.Flow
		edge.Ctime = time.Now()
		edge.Creater = user.Name
		edge.Utime = time.Now()
		edge.Updater = user.Name
		edge.Isdelete = 0
		edge.Status = 1
		beego.Debug(edge)
		edges = append(edges, &edge)
	}

	if err := models.CreateFlow(&flow.Flow, nodes, edges); err != nil {
		beego.Error(err)
		c.RetError(ErrDatabase)
	}
	c.Dlog("添加了流程,id是:", flow.Flow.Id)
	c.RetSuccess(flow)
}

// Delete ...
// @Title Delete
// @Description delete the Flow
// @Param	id		path 	string	true		"The id you want to delete"
// @Success 200 {string} delete success!
// @Failure 403 id is empty
// @router /Delete [post]
func (c *FlowController) Delete() {
	user := c.User
	rdata, err := c.AesDecode(c.GetString("tdata"))
	if err != nil {
		c.RetError(ErrToken)
	}
	sdata, _ := rdata.(map[string]interface{})
	id := sdata["Id"].(string)
	err = models.SoftDeleteFlow(id, user.Name)
	if err != nil {
		beego.Error(err)
		c.RetError(ErrDatabase)
	}
	c.Dlog("删除了流程", id)
	c.RetSuccess(id)
}

// GetBusyDoing ...
// @Title GetBusyDoing
// @Description get Flow by id
// @Param	id		path 	string	true		"The key for staticblock"
// @Success 200 {object} models.Flow
// @Failure 403  empty
// @router /GetBusyDoing [post]
func (c *FlowController) GetBusyDoing() {
	user := c.User
	rdata, err := c.AesDecode(c.GetString("tdata"))
	if err != nil {
		c.RetError(ErrToken)
	}
	beego.Debug(rdata)
	sdata, _ := rdata.(map[string]interface{})
	beego.Debug(sdata)
	busyName := sdata["busyName"].(string)
	var v []orm.Params

	if busyName == "sf_case" {
		v, err = models.GetSfCaseBusyDoing(user)
	} else  {
		v, err = models.GetBusyDoing(user, busyName)
	}
	beego.Debug(v)
	if err != nil {
		c.RetError(ErrNoData)
	}
	c.RetSuccess(v)
}

// GetBusyFlowing ...
// @Title GetBusyFlowing
// @Description get Flow by id
// @Param	id		path 	string	true		"The key for staticblock"
// @Success 200 {object} models.Flow
// @Failure 403  empty
// @router /GetBusyFlowing [post]
func (c *FlowController) GetBusyFlowing() {
	user := c.User
	rdata, err := c.AesDecode(c.GetString("tdata"))
	if err != nil {
		c.RetError(ErrToken)
	}
	sdata, _ := rdata.(map[string]interface{})
	busyName := sdata["busyName"].(string)

	v, err := models.GetBusyFlowing(user, busyName)
	if err != nil {
		c.RetError(ErrNoData)
	}
	c.RetSuccess(v)
}


// GetAssetsbuyCompleted ...
// @Title GetAssetsbuyCompleted
// @Description get Flow by id
// @Param	id		path 	string	true		"The key for staticblock"
// @Success 200 {object} models.Flow
// @Failure 403  empty
// @router /GetAssetsbuyCompleted [post]
func (c *FlowController) GetAssetsbuyCompleted() {
	user := c.User
	rdata, err := c.AesDecode(c.GetString("tdata"))
	if err != nil {
		c.RetError(ErrToken)
	}
	sdata, _ := rdata.(map[string]interface{})
	busyName := sdata["busyName"].(string)

	v, err := models.GetBusyFlowing(user, busyName)
	if err != nil {
		c.RetError(ErrNoData)
	}
	c.RetSuccess(v)
}

// GetAssetsbuyUserAndBusy ...
// @Title GetAssetsbuyUserAndBusy
// @Description get Flow by id
// @Param	id		path 	string	true		"The key for staticblock"
// @Success 200 {object} models.Flow
// @Failure 403  empty
// @router /GetAssetsbuyUserAndBusy [post]
func (c *FlowController) GetAssetsbuyUserAndBusy() {
	user := c.User
	rdata, err := c.AesDecode(c.GetString("tdata"))
	if err != nil {
		c.RetError(ErrToken)
	}
	sdata, _ := rdata.(map[string]interface{})
	busyName := sdata["busyName"].(string)

	v, err := models.GetBusyFlowingByUser(user, busyName)
	if err != nil {
		c.RetError(ErrNoData)
	}
	c.RetSuccess(v)
}

// GetBusyFinish ...
// @Title GetBusyFinish
// @Description get Flow by id
// @Param	id		path 	string	true		"The key for staticblock"
// @Success 200 {object} models.Flow
// @Failure 403  empty
// @router /GetBusyFinish [post]
func (c *FlowController) GetBusyFinish() {
	user := c.User
	rdata, err := c.AesDecode(c.GetString("tdata"))
	if err != nil {
		c.RetError(ErrToken)
	}
	sdata, _ := rdata.(map[string]interface{})
	busyName := sdata["busyName"].(string)

	v, err := models.GetBusyFinish(user, busyName)
	if err != nil {
		c.RetError(ErrNoData)
	}
	c.RetSuccess(v)
}

// FlowStart ...
// @Title FlowStart
// @Description 申请上报
// @Param	body		body 	models.Flow	true		"body for Assetsbuy content"
// @Success 201 {int} models.Flow
// @Failure 403 body is empty
// @router /FlowStart [post]
func (c *FlowController) FlowStart() {
	user := c.User
	rdata, err := c.AesDecode(c.GetString("tdata"))
	if err != nil {
		c.RetError(ErrToken)
	}
	sdata, _ := rdata.([]interface{})
	for _, value := range sdata {
		v, _ := value.(map[string]interface{})
		busyid := v["Id"].(string)
		busyName := v["busyName"].(string)
		busyTable := v["busyTable"].(string)
		beego.Debug("busyName:", busyName, "busyTable:", busyTable)
		flow, err := models.GetFlowByName(busyName)
		fins, err := models.InitFSM(user, flow.Id, busyTable, busyid)
		beego.Debug("fins err: ", fins) 
		fsm := models.GetFSM(fins)
		// // beego.Debug("fsm err: ", fsm)
		ev, _ := models.GetEventByName("上报")
		err = fsm.Trigger(fins.Currentstate, ev.Id, fins, user,"上报","上报" )
		err = models.SetBusyStart(busyid, busyTable)
		if err != nil {
			beego.Error("trigger1 err: ", err)
		}
		//c.Dlog("上报了销售订单", busyid)
		if busyTable == "sf_case" {
			fscase, _ := models.GetSfCaseById(busyid)
			fscase.AppointTime = time.Now()
			fscase.AppointUser = user.Abbr
			fscase.AppointUserId = user.Id
			models.UpdateSfCaseById(fscase)
		}
	}

	// ts, err := models.GetFlowinstanceByBusyId(busyid)
	// // 针对退回的单据重新生成流程实例
	// if ts.Status == 3 {
	// 	models.ReApply(user.Id, busyid, ts)
	// 	flow, _ := models.GetFlowByName("采购单")
	// 	ts, _ = models.InitFSM(user, flow.Id, "Assetsbuy", busyid)
	// }
	// beego.Debug("ts err: ", ts)
	// fsm := models.GetFSM(ts)
	// // beego.Debug("fsm err: ", fsm)
	// ev, _ := models.GetEventByName("上报")
	// err = fsm.Trigger(ts.Currentstate, ev.Id, ts)
	// if err != nil {
	// 	beego.Error("trigger err: ", err)
	// 	c.RetError(ErrPermission)
	// }

	c.RetSuccess(sdata)

}

// GetAssetsbuyDoing ...
// @Title GetAssetsbuyDoing
// @Description get Flow by id
// @Param	id		path 	string	true		"The key for staticblock"
// @Success 200 {object} models.Flow
// @Failure 403  empty
// @router /GetAssetsbuyDoing [post]
func (c *FlowController) GetAssetsbuyDoing() {
	user := c.User
	rdata, err := c.AesDecode(c.GetString("tdata"))
	if err != nil {
		c.RetError(ErrToken)
	}
	sdata, _ := rdata.(map[string]interface{})
	busyName := sdata["busyName"].(string)

	v, err := models.GetBusyDoing(user, busyName)
	if err != nil {
		c.RetError(ErrNoData)
	}
	c.RetSuccess(v)
}

// GetStateinsByBusy ...
// @Title GetStateinsByBusy
// @Description 申请上报
// @Param	body		body 	models.Stateinstance	true		"body for Assetsbuy content"
// @Success 201 {int} models.Stateinstance
// @Failure 403 body is empty
// @router /GetStateinsByBusy/:id [get]
func (c *FlowController) GetStateinsByBusy() {
	user := c.User
	id := c.Ctx.Input.Param(":id")
	//beego.Debug("GetStateinsByBusyGetStateinsByBusyGetStateinsByBusyGetStateinsByBusyGetStateinsByBusy")
	//beego.Debug("==========", id)
	v, err := models.GetStateinsByBusy(id)
	if err != nil {
		beego.Error(err)
		c.RetError(ErrNoData)
	}
	ct, err := models.GetCurrentByUser(user.Id, id)
	if err != nil {
		ct, err = models.GetCurrent(id)
	}

	jdata := make(map[string]interface{})
	var states []map[string]interface{}

	time2 := "2006-03-21 09:04:25"
	t, err := time.Parse("2006-01-02 15:04:05", time2)
	for k, s := range v {
		st := make(map[string]interface{})
		st["Text"] = s.Text
		st["Atime"] = s.Atime
		st["Approver"] = s.Approver
		st["Opinions"] = s.Opinions
		st["Result"] = s.Result
		st["Busyname"] = s.Busyname
		st["Busyid"] = s.Busyid
		st["Status"] = s.Status
		if ct.Id == s.Id {
			jdata["current"] = k
			// break
		}
		if s.Atime.Before(t) {
			st["Atime"] = nil
		}
		states = append(states, st)
	}
	jdata["states"] = states
	jdata["currentState"] = ct
	c.RetSuccess(jdata)
}

// FlowApprove ...
// @Title FlowApprove
// @Description 申请上报
// @Param	body		body 	models.Flow	true		"body for Assetsbuy content"
// @Success 201 {int} models.Flow
// @Failure 403 body is empty
// @router /FlowApprove [post]
func (c *FlowController) FlowApprove() {
	//beego.Debug("审核调用了FlowApprove（）方法？")
	user := c.User
	var v models.Stateinstance
	rdata, err := c.AesDecodeToByte(c.GetString("tdata"))
	if err != nil {
		c.RetError(ErrNoData)
	}

	beego.Debug(string(rdata))
	err = json.Unmarshal(rdata, &v)
	beego.Debug(v)
	if err != nil {
		c.RetError(ErrNoData)
	}
	fins, _ := models.GetFlowinstanceById(v.Flowinstance.Id)
	beego.Debug(fins.Status)
	//如果被驳回，则重新初始化流程
	//if fins.Status == 3 {
	//	models.ReApply(user.Id, v.Busyid, fins)
	//	flow, _ := models.GetFlowById(fins.Flow.Id)
	//	fins, err = models.InitFSM(user, flow.Id, v.Busyname, v.Busyid)
	//}
	tag := "同意"
	if v.Result != 1  {
		tag = "不同意"
	}
	// 如果被驳回，则重终止流程
	if fins.Status ==3 {
		models.StopFlow(user,  fins)
	}

	fsm := models.GetFSM(fins)
	var ev *models.Event
	if v.Result == 1 {
		ev, _ = models.GetEventByName("同意")
	} else {
		ev, _ = models.GetEventByName("不同意")
	}
	result := v.Result
	opinions := v.Opinions
	remark := v.Remark
	err = fsm.Trigger(v.Id, ev.Id, fins, user, opinions,remark, result)
	if err != nil {
		beego.Error("trigger1 err: ", err)
		ev, _ = models.GetEventByName("会签")
		err = fsm.Trigger(v.Id, ev.Id, fins, user.Abbr, opinions,remark, result)
	}
	if err != nil {
		beego.Error("trigger1 err: ", err)
		ev, _ = models.GetEventByName("上报")
		err = fsm.Trigger(v.Id, ev.Id, fins, user.Abbr, opinions, remark,result)
	}

	c.Dlog("流程变更",  user.Abbr + "审核结果为： "+tag )
	c.RetSuccess(v.Id)
}


// GetAssetsbuyFinish ...
// @Title GetAssetsbuyFinish
// @Description get Flow by busyname
// @Param	busyName		path 	string	true		"yjk_buy"
// @Success 200 {object} models.Flow
// @Failure 403  empty
// @router /GetAssetsbuyFinish [post]
func (c *FlowController) GetAssetsbuyFinish() {
	user := c.User
	rdata, err := c.AesDecode(c.GetString("tdata"))
	if err != nil {
		c.RetError(ErrToken)
	}
	sdata, _ := rdata.(map[string]interface{})
	busyName := sdata["busyName"].(string)

	v, err := models.GetBusyFinish(user, busyName)
	if err != nil {
		c.RetError(ErrNoData)
	}
	c.RetSuccess(v)
}